﻿using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Linq;
using System.Text;
using SlimDX;
using SlimDX.Direct3D10;
using ColladaLoader;


namespace SCS.GFX {
  public class ColoredMeshObject : MeshObject {


    DepthStencilStateDescription dssd = new DepthStencilStateDescription();
    DepthStencilState dss;

    Vector4 FColor;

    //Default constructor
    public ColoredMeshObject(MeshContainer m)
      : base(m) {

      dssd = new DepthStencilStateDescription();
      dssd.IsDepthEnabled = true;
      dssd.IsStencilEnabled = false;
      dssd.DepthWriteMask = DepthWriteMask.All;
      dssd.DepthComparison = Comparison.LessEqual;
      dss = DepthStencilState.FromDescription(Renderer.Device, dssd);

      //FEffect = Effect.FromFile(Renderer.Device, System.IO.Directory.GetCurrentDirectory() + "\\Effects\\PositionColored.fx", "fx_4_0", ShaderFlags.None, EffectFlags.None, null, null);
      FEffect = Effect.FromFile(Renderer.Device,"..\\..\\..\\..\\Effects\\PositionColored.fx", "fx_4_0", ShaderFlags.None, EffectFlags.None, null, null); 
        FTechnique = FEffect.GetTechniqueByIndex(0);
      //Get the first pass
      FPass = FTechnique.GetPassByIndex(0);


    }

    public override void LoadTextures(MeshContainer m) {
      foreach (EffectNode e in m.materials) {
        FColor = e.FDiffuse; //Fixme: at the moment, we just take the last mat in the list associated with the current mesh
      }
    }

    public override void LoadVertexBuffer(MeshContainer m) {

       FVerticeCount = m.vertices.Count;

      //Construct vertex buffer for drawing
      BufferDescription bufferDescription = new BufferDescription();
      bufferDescription.BindFlags = BindFlags.VertexBuffer;
      bufferDescription.CpuAccessFlags = CpuAccessFlags.None;
      bufferDescription.OptionFlags = ResourceOptionFlags.None;
      bufferDescription.SizeInBytes = FVerticeCount * PositionColored.SizeInBytes;
      bufferDescription.Usage = ResourceUsage.Default;


      DataStream stream = new DataStream(FVerticeCount * PositionColored.SizeInBytes, true, true);
      stream.Position = 0;

      foreach (SkinnedTangentVertex i in m.vertices) {
        stream.Write(new Vector3(i.pos.X, i.pos.Z, i.pos.Y));
        stream.Write(FColor);
      }

      stream.Position = 0;

      FVertexBuffer = new SlimDX.Direct3D10.Buffer(Renderer.Device, stream, bufferDescription);
      stream.Close();
    }

    public override void LoadIndexBuffer(MeshContainer m) {
      FIndexCount = m.indices.Length;

      DataStream indexstream = new DataStream(FIndexCount * 2, true, true); //(2bytes/index)
      indexstream.Position = 0;

      for (int i = 0; i < m.indices.Length; i++) {
        indexstream.Write(m.indices[i]);
      }
      indexstream.Position = 0;

      BufferDescription indexBufferDescription = new BufferDescription();
      indexBufferDescription.BindFlags = BindFlags.IndexBuffer;
      indexBufferDescription.CpuAccessFlags = CpuAccessFlags.None;
      indexBufferDescription.OptionFlags = ResourceOptionFlags.None;
      indexBufferDescription.SizeInBytes = FIndexCount * 2; //fixme
      indexBufferDescription.Usage = ResourceUsage.Default;

      FIndexBuffer = new SlimDX.Direct3D10.Buffer(Renderer.Device, indexstream, indexBufferDescription);

    }

    public override void Render(RenderInfo aInfo) {

      //Enable depth buffering
      //this.World = FPositionMatrix;
      //this.RotationY = -1.7f;

      //this.SetPosition(FPosition.X,FPosition.Y,FPosition.Z);
      //this.RotationX = 

      //StateManager.World = FWorldMatrix;

      Renderer.Device.OutputMerger.DepthStencilState = dss;

      //Set input layout and primitive topology
      Renderer.Device.InputAssembler.SetInputLayout(FLayout);
      Renderer.Device.InputAssembler.SetPrimitiveTopology(PrimitiveTopology.TriangleList);

      //Set vertex and index buffers
      Renderer.Device.InputAssembler.SetVertexBuffers(0, new VertexBufferBinding(FVertexBuffer, PositionColored.SizeInBytes, 0));
      Renderer.Device.InputAssembler.SetIndexBuffer(FIndexBuffer, SlimDX.DXGI.Format.R16_UInt, 0);

      /*
      //Set texture unites
      for (int i = 0; i > FTextureViews.Count; i++) {
        if (i == 0) StateManager.Tex2D_0 = FTextureViews[i].View;
        if (i == 1) StateManager.Tex2D_1 = FTextureViews[i].View;
        if (i == 2) StateManager.Tex2D_3 = FTextureViews[i].View;
      }
       * 
       */

      //      StateManager.Tex2D_0 = FTextureViews[0].View;

      RasterizerStateDescription FRasterizer = new RasterizerStateDescription();
      FRasterizer.CullMode = CullMode.Back;
      FRasterizer.FillMode = FillMode.Solid;
      FRasterizer.IsFrontCounterclockwise = false;
      FRasterizer.DepthBias = 0;
      FRasterizer.DepthBiasClamp = 0;
      FRasterizer.SlopeScaledDepthBias = 0;
      FRasterizer.IsDepthClipEnabled = false;
      FRasterizer.IsScissorEnabled = false;
      FRasterizer.IsMultisampleEnabled = false;
      FRasterizer.IsAntialiasedLineEnabled = false;

      Renderer.Device.Rasterizer.State = RasterizerState.FromDescription(Renderer.Device, FRasterizer);

      //Apply Shader pass(es)
      FPass.Apply();

      //Draw the mesh
      Renderer.Device.DrawIndexed(FIndexCount, 0, 0);

      /*
      RasterizerStateDescription FRasterizer2 = new RasterizerStateDescription();
      FRasterizer2.CullMode = CullMode.Back;
      FRasterizer2.FillMode = FillMode.Solid;
      FRasterizer2.IsFrontCounterclockwise = false;
      FRasterizer2.DepthBias = 0;
      FRasterizer2.DepthBiasClamp = 0;
      FRasterizer2.SlopeScaledDepthBias = 0;
      FRasterizer2.IsDepthClipEnabled = false;
      FRasterizer2.IsScissorEnabled = false;
      FRasterizer2.IsMultisampleEnabled = false;
      FRasterizer2.IsAntialiasedLineEnabled = false;

      Device.Rasterizer.State = RasterizerState.FromDescription(Device, FRasterizer2);
      */

    }

    public override void Dispose() {
      base.Dispose();

      if (FEffect != null)
        FEffect.Dispose();
      FEffect = null;


    }

  }
}
